package com.wzdigit.wms.basic.aop;

import com.wzdigit.framework.Shift;
import com.wzdigit.wms.basic.annotation.FormLock;
import com.wzdigit.wms.basic.service.code.RedisService;
import com.wzdigit.wms.basic.util.HttpSessionUtil;
import com.wzdigit.wms.basic.util.NetUtils;
import com.wzdigit.wms.basic.util.RequestUtils;
import com.wzdigit.wms.basic.util.StringUtils;
import com.wzdigit.wms.basic.util.common.LockNumber;
import com.wzdigit.wms.basic.util.common.LockString;
import com.wzdigit.wms.basic.util.common.MethodString;
import com.wzdigit.wms.basic.util.common.SeparatorString;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;

/**
 * 防止重复提交
 * 
 * @author Administrator
 */
@Slf4j
@Aspect
@Component
@SuppressWarnings("all")
@Order(1)	// 默认是最低优先级,值越小优先级越高
public class FormLockAspect {

	@Autowired
	private RedisService redisService;
	
	private final static String GET = MethodString.GET;
	private final static String POINT = SeparatorString.POINT;
	private final static String LOCK_KEY = LockString.WMS_SUBMIT_LOCK_KEY;

	@Pointcut("execution(* com.wzdigit.wms.*.controller.*..*.*(..))")
	public void reqLock() {
	}

	@Around("reqLock()")
	public Object constructionSite(ProceedingJoinPoint pjp) throws Throwable {
		HttpServletRequest request = RequestUtils.getRequest();
		MethodSignature methodSignature = (MethodSignature)pjp.getSignature();
		
		// 获取自定义注解
		FormLock formLock = methodSignature.getMethod().getAnnotation(FormLock.class);
		
		// 非GET请求或者加了注解的请求
		if (!GET.equals(request.getMethod()) || formLock != null) {
			long timeOut = LockNumber.SECONDS_II;				// 拦截时间
			if(formLock != null) {
				timeOut = formLock.seconds();
				if(!formLock.isdeal()) {
					return pjp.proceed();
				}
			}
			
			// 获取方法签名（通过此签名获取目标方法信息）
			String methodName = methodSignature.getName();				// 目标方法名
			String targetName = methodSignature.getDeclaringTypeName();	// 目标类名
			
			// 用户名
			String loginName = HttpSessionUtil.getLoginName(request);
			
			// 【WMS_SUBMIT_LOCK_KEY】 + 【.】 + 【目标类名】 + 【.】 + 【目标方法名】 + 【.】 + 【用户名/IP】
			StringBuffer lockKey = new StringBuffer();
			lockKey.append(LOCK_KEY).append(POINT).append(targetName).
			append(POINT).append(methodName).append(POINT);
			if (StringUtils.isNull(loginName)) {
				lockKey.append(NetUtils.getIpAddr(request));
			} else {
				lockKey.append(loginName);
			}
			
			// redis锁key
			String lockKeyStr = lockKey.toString().toUpperCase();
			log.info("重复提交校验KEY：" + lockKeyStr + "，锁定" + timeOut + "秒");
			if (redisService.lock(lockKeyStr, timeOut)) {
				try {
					Object result = pjp.proceed();
					return result;
				} catch (Exception e) {
					throw e;
				} finally {
					// 释放锁
					redisService.unlock(lockKeyStr);
				}
			} else {
				Shift.fatal("请勿重复提交");
				return null;
			}
		} else {
			return pjp.proceed();
		}
	}
}